<script>
import Anchor from './Anchor.vue';
import antoAnchor from './anchor.js';
import CdpFlowStart from './CdpFlowStart.vue';
import NotFound from './NotFound.vue';
import LazyLoader from './LazyLoader.vue';
// import {
//   getTreeData,
//   getPageGrpList,
//   getBtnControl
// } from '../apis';
import {
  findTreechild,
  requirecomponent,
  createProxy,
  setDefaultMain,
  traverseSetActiveName,
  getNodechildren,
  margeUserBtns,
  clearStore,
  callchildFunc,
  activePage,
  callAnchorFunc,
  setBusiBtnControl,
  getActivechild,
  filterNode,
  handleTreeData,
  isFunction,
  isObject,
  isString,
  extendContext,
  mergedAnchorPageData,
} from './util.js';

export default {
  name: 'PageFactory',
  components: { Anchor, CdpFlowStart, LazyLoader },
  directive: { auah: antoAnchor },
  props: {
    footerBtn: {
      type: Array,
      default: () => []
    },
    btnPos: String,
    params: {
      type: Array,
      default: () => [],
    },
    configData: {
      type: Array,
      default: () => []
    },
    visible: {
      type: Boolean,
      default: true
    },
  },
  data() {
    return {
      height: '',
      curPageNode: {},
      renderData: [],
      instanceVisible: true,
      busTyp: '',
      btnList: [],
      btnPosi: this.btnPos || 'bottom',
      show404: false,
    };
  },
  watch: {
    'params.pageGrpNo'(val, oldVal) {
      if (oldVal === '') {
        return;
      }
      this.init();
    },
  },
  activated() {
    if (!this.actived) {
      this.actived = true;
    } else {
      this.commonBtnclick('refresh', '2');
    }
  },
  beforeRouteLeave(to, from, next) {
    try {
      const cachedViews = this.$store.state.tagsView.cachedViews;
      const findIncache = cachedViews.find((v) => v.path === from.path);
      if (!findIncache) {
        //说明是关闭了路由，不是切换
        const keepAliveInstance = this.findKeepAlive();
        if (!keepAliveInstance) {
          return next();
        }
        const { cache } = keepAliveInstance;
        const cacheKeys = Object.keys(cache);
        const delKey = cacheKeys.find((key) => key.includes(from.path));
        delKey && (cache[delKey] = null);
        Reflect.deleteProperty(cache, delKey);
        this.$destroy(); //调用组件的销毁
      }
      next();
    } catch (error) {
      next();
    }
  },
  created() {
    console.log("render created");
    this.init();
  },

  mounted() {
    console.log("render mounted");
    this.calcHeight();
  },
  beforeDestroy() {
    clearStore(this.contextData.mainPagecde);
    this.clear()
    this.unRegisterComp()
  },
  methods: {
    unRegisterComp() {
      const components = this.$options.components
      const regExp = /^pf-page-/;
      for (const key in components) {
        if (regExp.test(key)) {
          components[key] = null
          delete components[key]
        }
      }
    },
    clear() {
      Object.keys(this.contextData).forEach(key => this.contextData[key] = null)
    },
    init(contextData) {
      !contextData && (this.instanceVisible = this.visible)
      this.handleParams(contextData);
      const { btnList, mainPageButnId } = this.contextData
      margeUserBtns(this.btnList, this.footerBtn, btnList, mainPageButnId === 'view');
      this.setConfigData()
      // const res = this.setBtncontrol();
      // res && res.then(this.setConfigData)
    },
    setBtncontrol() {
      // const { mainPagecde, mainPageButnId, pageGrpNo } = this.contextData;
      // if (mainPagecde && mainPageButnId) {
      //   return getBtnControl({ mainPagecde, mainPageButnId }).then((res) => {
      //     setBusiBtnControl(res.data, mainPagecde);
      //   });
      // } else if (pageGrpNo) {
      //   return Promise.resolve(1)
      // }
    },
    setRenderData(data) {
      console.log("setRenderData data", data);
      const main = handleTreeData(data);
      console.log("setRenderData main", main)
      filterNode(data, this.contextData);
      if (!main) {
        setDefaultMain(data, main)
        traverseSetActiveName(data)
      }
      this.renderData.splice(0, this.renderData.length, ...data);
      main && (this.curPageNode = main);
    },
    setConfigData() {
      let data = [{
        "pkId": "b1816f26af10be0baf1a7de805870901",
        "pageGrpNo": "demo42",
        "supPageNodeId": null,
        "pageNodeId": "2BF046417B224702A7E37AC6B850E457",
        "pageNodeName": "demo42",
        "pageNodeTyp": "02",
        "relPagecde": null,
        "pageseq": 3,
        "showMtd": "02",
        "nvgBarLo": "T",
        "saveMtd": null,
        "pageshowCnd": null,
        "sysFlteInd": null,
        "pageFlteCnd": "",
        "mtchUrl": null,
        "logiDelInd": "N",
        "crtUsr": "admin",
        "crtUsrName": "admin",
        "crtBch": "50@",
        "crtBchName": "宇信集团",
        "crtDt": "2025-05-09 10:47:35",
        "lastChgUsr": "admin",
        "lastChgUsrName": "admin",
        "lastchgBch": "500",
        "lastchgDt": "2025-05-09 14:51:22",
        "instucde": "F0001",
        "instuName": "示例金融机构",
        "children": [
          {
            "pkId": "PKAjF4qdp4hw1LcpJj",
            "pageGrpNo": "demo42",
            "supPageNodeId": "2BF046417B224702A7E37AC6B850E457",
            "pageNodeId": "IDqLg2Lw3577o1jp07",
            "pageNodeName": "房产类估值样本管理列表的副本",
            "pageNodeTyp": "01",
            "relPagecde": "estaEvlsampPageCopy",
            "mainPageInd": "Y",
            "pageseq": 1,
            "showMtd": null,
            "sysFlteInd": null,
            "nvgBarLo": null,
            "saveMtd": null,
            "pageShowcnd": null,
            "pageFlteCnd": "",
            "mtchUrl": "/cdp-crc/api/w/cdp_crc/dsbr/crcrepayaply/list",
            "logiDelInd": "N",
            "crtUsr": "admin",
            "crtBch": "50日",
            "crtDt": "2025-05-09 10:54:03",
            "lastChgUsr": "admin",
            "lastChgBch": "500",
            "lastchgDt": "2025-05-09 11:06:29",
            "instucde": "F0001",
            "children": [],
            "pageUrl": "tab1.vue"
          },
          {
            "pkId": "PfffAjF4qdp4hw1LcpJj",
            "pageGrpNo": "demo42",
            "supPageNodeId": "2BF046417B224702A7E37AC6B850E457",
            "pageNodeId": "IDqLg2Lw1111443577o1jp07",
            "pageNodeName": "房产类估值样本管理列表的副本2",
            "pageNodeTyp": "01",
            "relPagecde": "estaEvlsampPageCopy",
            "mainPageInd": "N",
            "pageseq": 1,
            "showMtd": null,
            "sysFlteInd": null,
            "nvgBarLo": null,
            "saveMtd": null,
            "pageShowcnd": null,
            "pageFlteCnd": "",
            "mtchUrl": "/cdp-crc/api/w/cdp_crc/dsbr/crcrepayaply/list",
            "logiDelInd": "N",
            "crtUsr": "admin",
            "crtBch": "50日",
            "crtDt": "2025-05-09 10:54:03",
            "lastChgUsr": "admin",
            "lastChgBch": "500",
            "lastchgDt": "2025-05-09 11:06:29",
            "instucde": "F0001",
            "children": [],
            "pageUrl": "tab2.vue"
          }
        ]
      }]
      // if (this.configData.length > 0) {
      //   this.setRenderData(this.configData)
      //   return;
      // }
      // if (this.contextData.pageGrpNo) {
      this.setRenderData(data
      )
      // getPageGrpList({ page: 1, size: 10, pageGrpNo: this.contextData.pageGrpNo }).then((res) => {
      //   if (res && res.data && res.data.length > 0) {
      //     this.busTyp = res.data[0].busTyp;
      //     this.contextData.busTyp = this.busTyp;
      //   }
      //   // 请求配置数据
      // });
      // getTreeData(this.contextData.pageGrpNo).then((res) => {
      //   if (res && res.data.length > 0) {
      //     this.setRenderData(res.data)
      //   } else {
      //     this.show404 = true
      //   }
      // });
    },
    handleParams(params) {
      const routeParams = this.$route.params;
      if (params) {
        this.contextData = params
      } else if (this.params) {
        // 组件方式使用
        this.contextData = this.params;
      } else if (this.$attrs['biz-page-data']) {
        this.contextData = Object.assign({}, this.$attrs['biz-page-data'])
      } else if (routeParams && JSON.stringify(routeParams) !== '{}') {
        this.contextData = { ...routeParams };
      } else {
        this.contextData = {};
      }
      if (!Reflect.has(this.contextData, 'data')) {
        this.contextData.data = {}
      }
      this.contextData.btnPosi && (this.btnPosi = this.contextData.btnPosi)
      const proxy = createProxy(this, ['reRender', 'setVisible', 'activePage', 'doFilterNode', 'getFlow',
        'setBtnVisiable', 'getPageFiltercondition', 'getPageByCode', 'getParamsExtendcontext', 'getMergedPageData',
        'getCurrentPage']);
      this.contextData.pfInstance = proxy;
    },
    handleNodeclick(pnode, data) {
      if (data.children && data.children.length > 0) {
        return
      }
      const beforeRes = this.callBeforeSwitch()
      if (beforeRes === false) {
        return
      }
      this.unRegisterComp()
      this.setActiveName(pnode, data.pageNodeName);
      this.curPageNode = data;
    },
    handleExpand(pnode, data) {
      if (pnode.expandKeys) {
        pnode.expandKeys.push(data.pkId)
      } else {
        this.$set(pnode, 'expandKeys', [data.pkId])
      }
    },
    handleCollapse(pnode, data) {
      if (pnode.expandKeys) {
        const index = pnode.expandKeys.indexOf(data.id)
        pnode.expandKeys.splice(index, 1)
      }
    },
    callBeforeSwitch() {
      const { pageNodeId, pageNodeName } = this.curPageNode;
      return callchildFunc(this, pageNodeId, pageNodeName, 'beforeSwitch')
    },
    tabBeforeLeaveFn() {
      const beforeRes = this.callBeforeSwitch()
      if (beforeRes === false) {
        return false
      }
      return true
    },
    handleTabclick(tab) {
      const beforeRes = this.callBeforeSwitch()
      if (beforeRes === false) {
        return
      }
      this.unRegisterComp()
      const { pnode, node } = tab.$attrs;
      this.setActiveName(pnode, node.pageNodeName);
      this.curPageNode = node;
    },
    getcurrentPage() {
      return this.$refs[this.curPageNode.pageNodeId]
    },
    doFilterNode(obj) {
      Object.assign(this.contextData, obj)
      filterNode(this.renderData, this.contextData);
    },
    debounce(fn, time) {
      let timer
      return (...argu) => {
        timer && clearTimeout(timer)
        //eslint-disable-next-line prefer-spread
        timer = setTimeout(() => fn.apply(null, argu) && clearTimeout(timer), time)
      }
    },
    calcHeight() {
      // const ck = document.querySelector('div.ck')
      // const parentHeight = ck.clientHeight
      // 32 parent padding 22 面包屑
      this.height = '100%' //parentHeight > 0 ? (parentHeight - 16 - 22) + 'px' : '100%';
    },
    setActiveName(node, activeName) {
      if (!activeName && Reflect.has(node, '__nodeActiveName')) return;
      const children = getNodechildren(node)
      if (!activeName && children.length > 0) {
        const main = children.find((n) => n.mainPageInd === '1');
        activeName = main ? main.pageNodeName : children[0].pageNodeName;
      }
      this.$set(node, '__nodeActiveName', activeName);
    },

    renderTree(node) {
      this.setActiveName(node);
      let curNodeKey = ''
      const children = getNodechildren(node)
      let child
      if (node.__nodeActiveName) {
        child = findTreechild(children, node.__nodeActiveName)
        while (child.children && child.children.length > 0) {
          child = findTreechild(children, child.nodeActiveName)
        }
      } else if (children && children[0]) {
        child = children[0]
      }
      child && (curNodeKey = child.pkId)
      const localData = children.filter((c) => c.visible !== false)
      return (
        <div class="t">
          <div class="tl" style={{ height: `calc(${this.height}-64px)` }}>
            <yu-xtree
              default-expanded-keys={node.expandKeys || []}
              current-node-key={curNodeKey}
              on-node-expand={(data) => this.handleExpand(node, data)}
              on-node-collapse={(data) => this.handleCollapse(node, data)}
              on-node-click={(data, n) => this.handleNodeclick(node, data, n)}
              local-data={localData}
              data-type="tree"
              node-key="pkId"
              data-id="pageNodeId"
              data-label="pageNodeName"
              data-pid="supPageNodeId"
              data-root="θ">
            </yu-xtree>
          </div>
          <div class="tr">
            {child ? this.renderNode(child) : null}
          </div>
        </div >
      )
    },

    // 渲染Tab
    renderTab(node) {
      const map = {
        L: 'left',
        T: 'top',
        B: 'bottom',
        R: 'right',
      }
      const include = ["pf-anchor-tab"]
      const lazy = this.contextData.tabLazy
      this.setActiveName(node);
      const children = getNodechildren(node)
      const activeName = node.__nodeActiveName || (children[0] ? children[0].pageNodeName : '')
      return (
        <el-tabs
          value={activeName}
          tab-position={map[node.nvgBarLo] || 'top'}
          before-leave={this.tabBeforeLeaveFn}
          on-tab-click={this.handleTabclick}
        >
          {this._l(children, (tab) => {
            return tab.visible ? (
              <el-tab-pane label={tab.pageNodeName} name={tab.pageNodeName} pnode={node} node={tab}>
                <keep-alive include={include}>
                  {
                    (lazy === false || tab.pageNodeName === node.__nodeActiveName) ? this.renderNode(tab) : null
                  }
                </keep-alive>
              </el-tab-pane>) : null
          })}
        </el-tabs>
      );
    },

    renderAnchor(node) {
      const directives = [
        { name: 'auah' }
      ]
      const lazy = this.contextData.anchorLazy
      const children = getNodechildren(node)
      const keys = children.map((c) => ({ id: c.pageNodeId, name: c.pageNodeName }))
      return (
        <div class="ah" ref="ah" {...{ directives }}
          data-anchor={JSON.stringify(keys)}
        >
          {this._l(children, (n) => {
            if (!n.visible) {
              return null;
            }
            return lazy ? <lazy-loader>{this.renderNode(n)}</lazy-loader> : this.renderNode(n);
          })}
          <el-backtop target=".ah" right={32} bottom={32}></el-backtop>
        </div>
      )
    },

    renderPage(pageUrl, pageNodeId, node) {
      const pageNodeIdName = 'pf-page-' + pageNodeId.toLowerCase()
      console.log("renderPage", pageNodeIdName)
      let compobj
      if (!this.$options.components[pageNodeIdName]) {
        try {
          console.log("renderPage,pageUrl", pageUrl);
          compobj = pageUrl ? requirecomponent(pageUrl) : NotFound
        } catch (error) {
          compobj = NotFound
          console.error(`PAGEFACTORY_ERROR:加载子页面 ${pageUrl} 报错`);
        }
        this.$options.components[pageNodeIdName] = compobj
      }
      const { mainPagecde } = this.contextData;
      return this.$refs[pageNodeId] ? this.$refs[pageNodeId].$vnode : (
        <pageNodeIdName
          ref={pageNodeId}
          id={node.pageNodeId}
          childPage={node.relPagecde}
          pageNo={node.relPagecde}
          contextData={this.contextData}
          btnctlPrefix={`${mainPagecde}_${pageNodeId}_`}
          key={node.relPagecde}
        ></pageNodeIdName>
      )
    },

    renderNode(node) {
      if (!node) {
        return null;
      }
      const { showMtd, pageNodeId, pageUrl } = node;
      if (showMtd === '01') {
        // 树
        return this.renderTree(node);
      }
      else if (showMtd === '02') {
        console.log("this.renderTab", node)
        // tab
        return this.renderTab(node);
      }
      else if (showMtd === '03') {
        // 锚点
        return this.renderAnchor(node);
      } else if (!showMtd && pageUrl) {
        // 页面节点
        return this.renderPage(pageUrl, pageNodeId, node);
      }
      return null;
    },

    back() {
      this.$emit('close')
      if (this.contextData['back'] && isFunction(this.contextData['back'])) {
        return this.contextData['back'](this.contextData);
      }
      const { pageNodeId, pageNodeName, showMtd } = this.curPageNode;
      if (showMtd) {
        return this.defaultclose();
      }
      const beforeHookRes = callchildFunc(this, pageNodeId, pageNodeName, 'beforeBack');
      if (beforeHookRes && isString(beforeHookRes)) {
        this.$confirm(beforeHookRes, '提示', {
          confirmButtonText: '是', cancelButtonText: "否",
          type: 'warning',
        }).then((res) => { this.defaultclose(); });
      }
      else if (beforeHookRes && isObject(beforeHookRes)) {
        this.defaultclose(beforeHookRes);
      }
      else if (beforeHookRes === false) {
        return;
      }
      else {
        this.defaultclose();
      }
    },

    defaultclose(params) {
      if (this.contextData.curRoute && typeof this.contextData.curRoute === 'string') {
        if (params) {
          const arr = this.contextData.curRoute.split('/');
          arr.pop();
          const goal = arr.pop() || 'goal';
          this.$router.closeTab(null, {
            path: this.contextData.curRoute,
            source: 'NewPageFactory',
            goal,
            back: true,
            params,
          });
        }
        else {
          this.$router.closeTab(null, {
            path: this.contextData.curRoute
          })
        }
      } else {
        this.$router.closeTab(null);
      }
    },

    getFlow() {
      return this.$refs.workflow;
    },

    getPageByCode(code) {
      const c = getNodechildren(this.curPageNode)
      if (!c || (c && c.length === 0)) {
        return null
      }
      const tar = c.find(page => page.relPagecde === code)
      if (tar) {
        return this.$refs[tar.pageNodeId]
      }
    },

    commonBtnclick(funcName, mtd) {
      const { pageNodeId, pageNodeName, showMtd } = this.curPageNode;
      if (this.contextData[funcName] && isFunction(this.contextData[funcName])) {
        return this.contextData[funcName](this.contextData);
      }
      if (showMtd === '03') {
        if (this.$refs.ah) {
          const children = getNodechildren(this.curPageNode)
          let lastShowPage = ''
          children.forEach(item => {
            if (item.visible === true) {
              lastShowPage = item.pageNodeId
            }
          })
          if (!this.$refs[lastShowPage] && ['tempSave', 'save', 'commit'].includes(funcName)) {
            return this.$confirm('未加载的页面内容将不会被保存，请确认是否继续保存?', '提示', {
              confirmButtonText: '是',
              cancelButtonText: '否',
              type: 'warning'
            }).then(() => {
              return callAnchorFunc(this, this.curPageNode, funcName, mtd)
            })
          } else {
            callAnchorFunc(this, this.curPageNode, funcName, mtd);
          }
        }
      }
      callchildFunc(this, pageNodeId, pageNodeName, funcName)
    },

    renderBtn() {
      const showBtns = this.btnList.filter((btn) => btn.show !== false).sort((a, b) => a.sort - b.sort);
      return (
        <yu-button-drop
          show-length={10} style="width: 100%;text-align: center;"
        >
          {this._l(showBtns, (btn) => {
            const styleobj = {};
            const { pageTyp, mainPageInd, relPagecde } = this.curPageNode;
            if ('save,tempsave'.includes(btn.funcName)) {
              styleobj.display = pageTyp === '01' ? '' : 'none';
            } else if (btn.funcName === 'commit') {
              styleobj.display = mainPageInd === 'Y' && this.busTyp ? '' : 'none';
            } else if (btn.showcondition) {
              styleobj.display = relPagecde === btn.showcondition ? '' : 'none';
            }
            return (
              <yu-button
                type={btn.type}
                onclick={btn.funcName == 'back' ? this.back : () => this.commonBtnclick(btn.funcName)}
                style={styleobj}
              >
                {btn.name}
              </yu-button>
            )
          })}
        </yu-button-drop >
      );
    },

    setBtnVisiable(btns, visiable) {
      this.btnList.forEach((btn) => {
        if (btns.includes(btn.name) || btns.includes(btn.funcName)) {
          btn.show = visiable
        }
      })
    },

    getParamsExtendcontext(obj) {
      return extendContext.call(this, obj)
    },

    getMergedPageData() {
      if (this.curPageNode.showMtd === '03') {
        return mergedAnchorPageData.call(this)
      }
    },

    getPageFiltercondition(node = this.curPageNode) {
      let { pageFlteCnd, relPageCde } = node;
      if (!pageFltecnd) {
        const activeNode = getActivechild(this)
        pageFlteCnd = activeNode.pageFlteCnd
        relPageCde = activeNode.relPageCde
      }
      if (!pageFltecnd) {
        return
      }
      const res = { pageGrpNo: this.contextData.pageGrpNo, relPagecde }
      const keys = pageFltecnd.split(';')
      keys.forEach(key => res[key] = this.contextData[key] || this.contextData.data[key])
      return window.btoa(window.encodeURI(JSON.stringify(res)))
    },
    activePage(pagecode) {
      const current = activePage.call(this, pagecode)
      this.curPageNode = current
      //调用afterswitch
      if (current && this.$refs[current.pageNodeId] && this.$refs[current.pageNodeId]['afterswitch']) {
        try {
          this.$refs[current.pageNodeId]['afterswitch']();
        } catch (error) {
          console.error(`PAGEFACTORY_ERROE:调用子页面 ${pagecode}的 afterswitch 方法报错`);
        }
      }
    },
    setVisible(bool) {
      this.instanceVisible = !!bool
    },

    reRender(contextData) {
      clearStore(this.contextData.mainPagecde);
      this.contextData = null
      this.btnList.splice(0)
      this.renderData.splice(0)
      this.init(contextData)
    }
  },
  render() {
    console.log("render this.renderData", this.renderData);
    if (this.renderData.length === 0 || !this.instanceVisible) {
      return this.show404 ? <NotFound page-grp-no={this.contextData.pageGrpNo} /> : <div />;
    }
    const topRightBtn = this.renderData[0].showMtd === '02' && this.btnPosi === 'topRight'
    const haveShowBtn = this.btnList.filter(btn => btn.show !== false)
    let height = 'calc(100% - 64px)'
    if (!this.contextData.mainPageButnId || topRightBtn || haveShowBtn.length === 0) {
      height = '100%'
    }
    return (
      <div
        class="pf auto"
        style={{ minHeight: this.height }}>
        <div
          class="pf-container"
          style={{ height }}
        >{this.renderNode(this.renderData[0])}</div>
        {(this.contextData.mainPageButnId && haveShowBtn.length > 0) ?
          <div class={topRightBtn ? 'pf-btn top-right' : 'pf-btn'}>{this.renderBtn()}</div> : null
        }
        {this.busTyp ? <CdpFlowStart ref="workflow" bizType={this.busTyp} oncomplete={this.back} /> : null}
      </div>
    )
  }
}
</script>
